package jaux.tank.service.system.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import jaux.tank.bean.dto.NoticeDto;
import jaux.tank.bean.dto.NoticeQuery;
import jaux.tank.bean.entity.system.Notice;
import jaux.tank.bean.entity.system.User;
import jaux.tank.bean.vo.EntityQueryCondition;
import jaux.tank.dao.enums.EntityQueryParamType;
import jaux.tank.dao.system.SysNoticeRepository;
import jaux.tank.dao.system.UserRepository;
import jaux.tank.dao.utils.JpaUtils;
import jaux.tank.service.system.NoticeService;
import jaux.tank.shiro.ShiroKit;
import jaux.tank.utils.PageUtils;
import jaux.tank.utils.factory.Page;

@Service
public class NoticeServiceImpl implements NoticeService {

	private final SysNoticeRepository noticeRepository;
	
	private final UserRepository userRepository;
	
	public NoticeServiceImpl(SysNoticeRepository noticeRepository, UserRepository userRepository) {
		this.userRepository = userRepository;
		this.noticeRepository = noticeRepository;
	}
	
	@Override
	public Page<Notice> query(NoticeQuery query, Page<Notice> defaultPage) {
		org.springframework.data.domain.Page<Notice> opage = noticeRepository.findAll(JpaUtils.genPredicate(query, Notice.class),
				PageUtils.convertPageToPageable(defaultPage));
		defaultPage.setTotal(opage.getTotalElements());
		defaultPage.setRecords(opage.getContent());
		return defaultPage;
	}

	@Override
	public NoticeDto updateNotice(NoticeDto notice) {
		Optional<Notice> noticeOpt = noticeRepository.findById(notice.getId());
		if(!noticeOpt.isPresent()) {
			return null;
		}
		Notice old = noticeOpt.get();
    	old.setTitle(notice.getTitle());
    	old.setContent(notice.getContent());
    	old.setType(notice.getType());
    	old.setIcon(notice.getIcon());
    	old.setReceiverFilterType(notice.getReceiverFilterType());
    	old.setReceivers(notice.getReceivers());
    	BeanUtils.copyProperties(noticeRepository.save(old), notice);
        return 	notice;
        	
	}
	
	@Override
	public Page<Notice> queryUserNotices(String userId, Page<Notice> defaultPage) {
		return queryUserNotices(userId, null, defaultPage);
	}
	
	@Override
	public Page<Notice> queryUserNotices(String userId, NoticeQuery query, Page<Notice> defaultPage) {
		User user = userRepository.findById(userId).orElse(null);
		if(user == null) {
			return null;
		}
		List<EntityQueryCondition> conditions = new ArrayList<>();
    	conditions.add(new EntityQueryCondition(Notice.Fields.receiverFilterType, Notice.ReceiverFilterType.ALL));
    	conditions.add(new EntityQueryCondition(Notice.Fields.receiverFilterType, EntityQueryParamType.IS_NULL, true));
		EntityQueryCondition userTypeReceiverCondition = new EntityQueryCondition(Notice.Fields.receiverFilterType, EntityQueryParamType.AND);
		userTypeReceiverCondition.setConditions(Arrays.asList(
				new EntityQueryCondition(Notice.Fields.receiverFilterType, Notice.ReceiverFilterType.USER),
				new EntityQueryCondition(Notice.Fields.receivers, EntityQueryParamType.CONTAINS, user.getId())
			));
		conditions.add(userTypeReceiverCondition);
		
		EntityQueryCondition deptTypeReceiverCondition = new EntityQueryCondition(Notice.Fields.receiverFilterType, EntityQueryParamType.AND);
		deptTypeReceiverCondition.setConditions(Arrays.asList(
				new EntityQueryCondition(Notice.Fields.receiverFilterType, Notice.ReceiverFilterType.DEPT),
				new EntityQueryCondition(Notice.Fields.receivers, EntityQueryParamType.CONTAINS,user.getDeptid())
			));
		conditions.add(deptTypeReceiverCondition);
		
		EntityQueryCondition roleTypeReceiverCondition = new EntityQueryCondition(Notice.Fields.receiverFilterType, EntityQueryParamType.AND);
		EntityQueryCondition userReceiversCondition = new EntityQueryCondition(Notice.Fields.receivers, EntityQueryParamType.OR);
		userReceiversCondition.setConditions(Arrays.stream(user.getRoleid().split(","))
				.map(role->new EntityQueryCondition(Notice.Fields.receivers, EntityQueryParamType.CONTAINS,role))
				.collect(Collectors.toList()));
		roleTypeReceiverCondition.setConditions(Arrays.asList(
				new EntityQueryCondition(Notice.Fields.receiverFilterType, Notice.ReceiverFilterType.ROLE),
				userReceiversCondition
			));
		conditions.add(roleTypeReceiverCondition);
		
	    	
		Specification<Notice> userQuerySpec = JpaUtils.genPredicateByConditions(
        	conditions,
	        Notice.class,
	        true
        );
		Specification<Notice> querySpec = null;
		if(query!=null) {
			querySpec = JpaUtils.genPredicate(query, Notice.class);
		}
		if(querySpec!=null ) {
			userQuerySpec = userQuerySpec.and(querySpec);
		}
		
		org.springframework.data.domain.Page<Notice> notices =  noticeRepository.findAll(userQuerySpec, PageUtils.convertPageToPageable(defaultPage));
		defaultPage.setTotal(notices.getTotalElements());
		defaultPage.setRecords(notices.getContent());
		return defaultPage;
	}
}
